package org.zjx.analysis.analyze.window;

import org.zjx.analysis.analyze.AbstractImageAnalyzer;
import org.zjx.analysis.identify.IdentifyFontUtil;
import org.zjx.command.entity.GameMouse;
import org.zjx.command.entity.ParagraphBean;
import org.zjx.command.entity.Rect;
import org.zjx.command.enums.FontType;
import org.zjx.command.util.ImageUtil;
import org.zjx.window.window.IWindow;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public abstract class AbstractWindowAnalyzer extends AbstractImageAnalyzer {
    protected final BufferedImage screenshot;
    protected final IWindow window;

    public Rectangle windowArea;

    public AbstractWindowAnalyzer(String analyzerName, String sceneType,IWindow window) {
        super(analyzerName, sceneType);
        this.window = window;
        this.screenshot = copy(window.getScreenshot());
        baseAnalysis();
    }

    private BufferedImage copy(BufferedImage screenshot) {
        // 创建副本，以避免对原图像产生影响
        BufferedImage copy = new BufferedImage(screenshot.getWidth(), screenshot.getHeight(), BufferedImage.TYPE_INT_ARGB);
        copy.getGraphics().drawImage(screenshot, 0, 0, null);
        return copy;
    }

    private void baseAnalysis() {
        if (getRefImage() == null) {
            analyze(screenshot);
            return;
        }
        List<Point> points = ImageUtil.matchTemplate(screenshot, getRefImage());
        if (points.isEmpty()) return;
        this.windowArea = getOriginBoundsNow(points.get(points.size() - 1));

        if (!isOpened() || isTransborder()) return;
        analyze(screenshot);
    }

    private Rectangle getOriginBoundsNow(Point point) {
        int offX = point.x - conversion(getOriginBounds(), getRefImageArea()).x;
        int offY = point.y - conversion(getOriginBounds(), getRefImageArea()).y;
        return new Rectangle(getOriginBounds().x + offX, getOriginBounds().y + offY, getOriginBounds().width, getOriginBounds().height);
    }

    //是否越界
    public boolean isTransborder() {
        if (windowArea == null) return false;
        return (windowArea.x < 0 || windowArea.y < 0 || windowArea.x + windowArea.width > window.getTrueBounds().width || windowArea.y + windowArea.height > window.getTrueBounds().height);
    }

    @Override
    protected boolean isSceneMatch(BufferedImage image) {
        return true;
    }

    protected abstract void initResources();

    public abstract Rectangle closeArea();

    public abstract Rectangle getOriginBounds();

    public abstract Rectangle getRefImageArea();

    public abstract BufferedImage getRefImage();


    public boolean isOpened() {
        return windowArea != null;
    }

    public Rectangle getCloseButtonPoint() {
        return closeArea() == null ? null : conversion(windowArea, closeArea());
    }

    public BufferedImage getSpecifiedAreaImage(Rectangle specified) {
        Rectangle rectangle = conversion(windowArea, specified);
        return ImageUtil.cutImage(screenshot, rectangle);
    }

    public Rectangle conversion(Rectangle windowArea, Rectangle rect) {
        return new Rectangle(rect.x + windowArea.x, rect.y + windowArea.y, rect.width, rect.height);
    }

    public Rectangle conversionReverse(Rectangle windowArea, Rectangle rect) {
        return new Rectangle(rect.x - windowArea.x, rect.y - windowArea.y, rect.width, rect.height);
    }

    protected boolean haveImage(ResolutionImage resolutionImage) {
        Rectangle bounds = conversion(windowArea, resolutionImage.getRectangle());
        BufferedImage background = ImageUtil.cutImage(screenshot, bounds);
        List<Point> points = ImageUtil.matchTemplate(background, resolutionImage.getPattern());
        return !points.isEmpty();
    }

    protected boolean haveButton(ResolutionImage resolutionImage) {
        Rectangle bounds = conversion(windowArea, resolutionImage.getRectangle());
        BufferedImage background = ImageUtil.cutImage(screenshot, bounds);
        BufferedImage bufferedImage = ImageUtil.makeColorsTransparent(resolutionImage.getPattern(), Collections.singletonList(Color.WHITE));
        List<Point> points = ImageUtil.matchTemplate(background, bufferedImage);
        return !points.isEmpty();
    }

    protected List<ParagraphBean.Word> identifyFont(Rectangle rectangle) {
        return identifyFont(rectangle, Collections.singletonList(new Color(176, 184, 200)), FontType.LIN, 0, true);
    }

    protected List<ParagraphBean.Word> identifyFont(Rectangle rectangle, List<Color> colors, FontType fontType, int height, boolean reverse) {
        BufferedImage image = ImageUtil.cutImage(screenshot, rectangle);
        return IdentifyFontUtil.identify(image,colors,IdentifyFontUtil.getFontAttributes(fontType),height,reverse);
    }

    protected String wordToStr(List<ParagraphBean.Word> words) {
        if (words == null || words.isEmpty()) return null;
        StringBuilder sb = new StringBuilder();
        for (ParagraphBean.Word word : words) {
            sb.append(word.getName());
        }
        return sb.toString();
    }

    public boolean mouseInRect(Rectangle rect) {
        GameMouse gameMouse = window.getState().getGameState().getGameMouse();
        return gameMouse != null && gameMouse.rectangle.intersects(rect);
    }

    public Point findLargestRemainingAreaCenter(Rectangle rect) {
        Rect[] candidates = getCandidates(rect);
        Rect largest = Arrays.stream(candidates).filter((r) -> r.getWidth() > 0 && r.getHeight() > 0).max(Comparator.comparingInt((r) -> r.getWidth() * r.getHeight())).orElse(
                new Rect(0, 0, window.getTrueBounds().width, window.getTrueBounds().height)
        );
        return largest.getCenter();
    }

    private Rect[] getCandidates(Rectangle rect) {
        int rectLeft = Math.max(rect.x, 0);
        int rectRight = Math.min(rect.x + rect.width, window.getTrueBounds().width);
        int rectTop = Math.max(rect.y, 0);
        int rectBottom = Math.min(rect.y + rect.height, window.getTrueBounds().height);
        return new Rect[]{
                new Rect(0, 0, rectLeft, window.getTrueBounds().height),
                new Rect(rectRight, 0, window.getTrueBounds().width, window.getTrueBounds().height),
                new Rect(0, 0, window.getTrueBounds().width, rectTop),
                new Rect(0, rectBottom, window.getTrueBounds().width, window.getTrueBounds().height)
        };
    }
}
